﻿using Engine;
using GameEntitySystem;
using TemplatesDatabase;
using Game;

namespace MFTrain
{
    public class ComponentMFEngine : ComponentInventoryBase, IUpdateable
    {
        public Point3 Coordinates { get; set; }
        public Vector3 Position { get; set; }
        public UpdateOrder UpdateOrder => UpdateOrder.Default;
        public float Work { get; private set; }

        private SubsystemTerrain subsystemTerrain;
        private SubsystemParticles subsystemParticles;
        private SubsystemPickables subsystemPickables;
        private SubsystemAudio subsystemAudio;
        private ComponentPlayer ridingPlayer;
        public ComponentPlayer RigingPlayer => ridingPlayer;

        public float waterVolumn;
        public float fireTimeRemaining;
        public float fuelLevel;
        private float waterConsumingSpeed = 0.0015f;
        public bool engineBreak = false;

        public override int GetSlotCapacity(int slotIndex, int value)
        {
            bool accept = false;
            if (slotIndex == 0)//燃料
            {
                Block blk = BlocksManager.Blocks[Terrain.ExtractContents(value)];
                accept = blk.GetFuelHeatLevel(value) > 0;
            }
            else if (slotIndex == 1)//水
            {
                Block blk = BlocksManager.Blocks[Terrain.ExtractContents(value)];
                accept = blk is WaterBucketBlock;
            }
            return accept ? base.GetSlotCapacity(slotIndex, value) : 0;
        }
        public override void AddSlotItems(int slotIndex, int value, int count)
        {
            if (slotIndex == 1)
            {
                Block blk = BlocksManager.Blocks[Terrain.ExtractContents(value)];
                if (blk is WaterBucketBlock)
                {
                    if (waterVolumn + 0.1f * count > 1f)
                    {
                        subsystemParticles.AddParticleSystem(new WaterSplashParticleSystem(subsystemTerrain, Position + new Vector3(0, 0.5f, 0), true));
                        FindNearestPlayer().ComponentGui.DisplaySmallMessage("水箱满啦！水全溢出来了\n(用来洗车倒还不错)", Color.White, true, false);
                        subsystemAudio.PlayRandomSound("Audio/Splashes", 1f, m_random.Float(-0.2f, 0.2f), Position, 6f, autoDelay: true);
                    }

                    waterVolumn = MathUtils.Clamp(waterVolumn + 0.1f * count, 0, 1);//加水的逻辑
                    if (ridingPlayer != null)//有骑乘的玩家
                    {
                        int notAcquireBucketNum = AcquireItems(ridingPlayer.ComponentMiner.Inventory, EmptyBucketBlock.Index, count);//尝试让玩家接受空桶
                        if (notAcquireBucketNum > 0)
                        {
                            subsystemPickables.AddPickable(EmptyBucketBlock.Index, notAcquireBucketNum, Position + new Vector3(0, 1.2f, 0), ridingPlayer.ComponentBody.Velocity, null);//添加空桶掉落物
                        }
                    }
                    else subsystemPickables.AddPickable(EmptyBucketBlock.Index, count, Position + new Vector3(0, 1.2f, 0), null, null);//添加空桶掉落物
                }
                else
                {
                    base.AddSlotItems(slotIndex, value, count);
                }
            }
            else
            {
                base.AddSlotItems(slotIndex, value, count);
            }
        }
        public void Update(float dt)
        {
            Work = engineBreak ?
                0 :
                (fireTimeRemaining > 0f && waterVolumn > 0 ? fuelLevel : 0);

            if (!engineBreak) EngineWorking(dt);//如果没有制动，则引擎工作
        }

        private void EngineWorking(float dt)//蒸汽机工作的方法
        {
            if (fireTimeRemaining <= 0f)//没有燃烧时间了
            {
                if (fuelLevel > 0) fuelLevel = 0;//无燃烧时间，燃料等级归零

                if (GetSlotCount(0) > 0)//燃料添加逻辑
                {
                    int value = GetSlotValue(0);
                    Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
                    if (!(block is WaterBucketBlock || block.GetFuelFireDuration(value) <= 0 || waterVolumn <= 0))//放入的是正确的燃料，并且水量大于0
                    {
                        fireTimeRemaining = block.GetFuelFireDuration(value);
                        fuelLevel = block.GetFuelHeatLevel(value);
                        m_slots[0].Count--;
                    }
                }
            }
            else//有燃烧时间
            {
                if (waterVolumn > 0)//水量大于0，执行蒸汽机逻辑
                {
                    fireTimeRemaining = MathUtils.Max(0, fireTimeRemaining - dt);
                    waterVolumn = MathUtils.Max(0, waterVolumn - dt * waterConsumingSpeed * MathUtils.Min(fuelLevel, 20));
                }
                if (waterVolumn <= 0)//水量小于0，燃烧时间也清零
                {
                    fireTimeRemaining = 0;
                }
            }
        }
        public void SetRidingPlayer(ComponentPlayer player)
        {
            if (ridingPlayer == player) return;
            ridingPlayer = player;
        }
        public Color GetLocalWaterColor()
        {
            return BlockColorsMap.WaterColorsMap.Lookup(subsystemTerrain.Terrain, Coordinates.X, Coordinates.Y, Coordinates.Z);
        }
        public ComponentPlayer FindNearestPlayer()
        {
            return Project.FindSubsystem<SubsystemPlayers>(throwOnError: true).FindNearestPlayer(Position);
        }

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
        {
            base.Load(valuesDictionary, idToEntityMap);
            subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>();
            subsystemParticles = Project.FindSubsystem<SubsystemParticles>();
            subsystemAudio = Project.FindSubsystem<SubsystemAudio>();
            subsystemPickables = Project.FindSubsystem<SubsystemPickables>();

            waterVolumn = valuesDictionary.GetValue<float>("WaterVolumn");
            fireTimeRemaining = valuesDictionary.GetValue<float>("FireTime");
            fuelLevel = valuesDictionary.GetValue<float>("FuelLevel");
            engineBreak = valuesDictionary.GetValue<bool>("Break");
        }
        public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
        {
            base.Save(valuesDictionary, entityToIdMap);
            valuesDictionary.SetValue("WaterVolumn", waterVolumn);
            valuesDictionary.SetValue("FireTime", fireTimeRemaining);
            valuesDictionary.SetValue("FuelLevel", fuelLevel);
            valuesDictionary.SetValue("Break", engineBreak);
        }
    }
}